#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include "time.h"

#include "MCP2515.h"

#define uint32_t  unsigned int

struct SpiMsg {
    unsigned char *wbuf;       /**< Address of the write buffer */
    unsigned char *rbuf;       /**< Address of the read buffer */
    uint32_t len;        /**< Length of the read and write buffers. The read buffer and the write
                          * buffer have the same length.
                          */
    uint32_t speed;      /**< Current message transfer speed */
    unsigned short delayUs;    /**< Delay (in microseconds) before starting the next transfer.
                          * The value <b>0</b> indicates there is no delay between transfers.
                          */
    unsigned char keepCs;    /**< Whether to keep CS active after current transfer has been
                          * completed. <b>1</b> indicates to keeps CS; <b>0</b> indicates to switch off the CS.
                          */
};

struct SpiIocMsg {
    struct SpiMsg *msg;
    int count;
};


#define SPI_IOC_MAGIC 'k'
#define SPI_IOC_MESSAGE                 _IOW(SPI_IOC_MAGIC, 0, struct SpiIocMsg)
#define SPI_IOC_RD_MODE                 _IOR(SPI_IOC_MAGIC, 1, uint32_t)
#define SPI_IOC_RD_LSB_FIRST            _IOR(SPI_IOC_MAGIC, 2, uint32_t)
#define SPI_IOC_RD_BITS_PER_WORD        _IOR(SPI_IOC_MAGIC, 3, uint32_t)
#define SPI_IOC_RD_MAX_SPEED_HZ         _IOR(SPI_IOC_MAGIC, 4, uint32_t)
#define SPI_IOC_WR_MODE                 _IOW(SPI_IOC_MAGIC, 1, uint32_t)
#define SPI_IOC_WR_LSB_FIRST            _IOW(SPI_IOC_MAGIC, 2, uint32_t)
#define SPI_IOC_WR_BITS_PER_WORD        _IOW(SPI_IOC_MAGIC, 3, uint32_t)
#define SPI_IOC_WR_MAX_SPEED_HZ         _IOW(SPI_IOC_MAGIC, 4, uint32_t)

//spidev0.0
#define DEV_NAME "/dev/spidev2.0"

void MCP2515_WriteByte(int spifd, unsigned char addr,unsigned char dat)
{
    unsigned char wbuf[3] = {CAN_WRITE, addr, dat};
    write(spifd, wbuf, 3);
}

unsigned char MCP2515_ReadByte(int spifd, unsigned char addr)
{
	unsigned char rByte;
    unsigned char wbuf[3] = {CAN_READ, addr, 0x00};
    struct SpiIocMsg iocmsg = {0};
    struct SpiMsg msg = {0};
    msg.wbuf = wbuf;
    msg.rbuf = wbuf;
    msg.len = 3;
    msg.speed=0;
    iocmsg.msg = &msg;
    iocmsg.count = 1;
    ioctl(spifd, SPI_IOC_MESSAGE, &iocmsg);
    rByte = wbuf[2];
	return rByte;				//返回读到的一个字节数据
}

void CAN_Send_Buffer(int spifd, unsigned char *CAN_TX_Buf,unsigned char len)
{
	unsigned char j,dly,count;

	count=0;
	while(count<len)
	{
		dly=0;
		while((MCP2515_ReadByte(spifd, TXB0CTRL)&0x08) && (dly<50))//快速读某些状态指令,等待TXREQ标志清零
		{
			// DoNanoSleep(1);//通过软件延时约nms(不准确)
            usleep(1);
			dly++;
		}
				
		for(j=0;j<8;)
		{
			MCP2515_WriteByte(spifd, TXB0D0+j, CAN_TX_Buf[count++]);//将待发送的数据写入发送缓冲寄存器
			j++;
			if(count>=len) break;
		}
		MCP2515_WriteByte(spifd, TXB0DLC, j);//将本帧待发送的数据长度写入发送缓冲器0的发送长度寄存器
		MCP2515_WriteByte(spifd, TXB0CTRL, 0x08);//请求发送报文
	}
    MCP2515_ReadByte(spifd, TXB0CTRL);
}


void MCP2515_Init(int spifd)
{ 
#if 1  
    usleep(1);
    	//设置波特率为125Kbps
	//set CNF1,SJW=00,长度为1TQ,BRP=49,TQ=[2*(BRP+1)]/Fsoc=2*50/8M=12.5us
	MCP2515_WriteByte(spifd, CNF1, 0x3);
	//set CNF2,SAM=0,在采样点对总线进行一次采样，PHSEG1=(2+1)TQ=3TQ,PRSEG=(0+1)TQ=1TQ
	MCP2515_WriteByte(spifd, CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ);
	//set CNF3,PHSEG2=(2+1)TQ=3TQ,同时当CANCTRL.CLKEN=1时设定CLKOUT引脚为时间输出使能位
	MCP2515_WriteByte(spifd, CNF3,PHSEG2_3TQ);
	
    MCP2515_WriteByte(spifd, TXB0SIDH,0xFF);//发送缓冲器0标准标识符高位
	MCP2515_WriteByte(spifd, TXB0SIDL,0xE0);//发送缓冲器0标准标识符低位
	
	MCP2515_WriteByte(spifd, RXB0SIDH,0x00);//清空接收缓冲器0的标准标识符高位
	MCP2515_WriteByte(spifd, RXB0SIDL,0x00);//清空接收缓冲器0的标准标识符低位
	MCP2515_WriteByte(spifd, RXB0CTRL,0x20);//仅仅接收标准标识符的有效信息
	MCP2515_WriteByte(spifd, RXB0DLC,DLC_8);//设置接收数据的长度为8个字节
	
	MCP2515_WriteByte(spifd, RXF0SIDH,0xFF);//配置验收滤波寄存器n标准标识符高位
	MCP2515_WriteByte(spifd, RXF0SIDL,0xE0);//配置验收滤波寄存器n标准标识符低位
	MCP2515_WriteByte(spifd, RXM0SIDH,0xFF);//配置验收屏蔽寄存器n标准标识符高位
	MCP2515_WriteByte(spifd, RXM0SIDL,0xE0);//配置验收屏蔽寄存器n标准标识符低位
	
	MCP2515_WriteByte(spifd, CANINTF,0x00);//清空CAN中断标志寄存器的所有位(必须由MCU清空)
	MCP2515_WriteByte(spifd, CANINTE,0x01);//配置CAN中断使能寄存器的接收缓冲器0满中断使能,其它位禁止中断
    MCP2515_ReadByte(spifd, CANCTRL);
	MCP2515_WriteByte(spifd, CANCTRL, REQOP_NORMAL | CLKOUT_ENABLED | OSM_ENABLED);//将MCP2515设置为正常模式,退出配置模式
    MCP2515_ReadByte(spifd, CANSTAT);
#endif
}
int main(int argc, char **argv)
{
    printf("\n************************************************\n");
    int fd = 0;

    fd = open(DEV_NAME, O_RDWR);
    if(fd == 0){
        printf("open %s failed error: %d\n",DEV_NAME, fd);
        return -1;
    }else{
        printf("open %s sucess fd: %d\n",DEV_NAME, fd);
    }
    unsigned long arg = 3;
    ioctl(fd, SPI_IOC_WR_MODE, &arg);
    arg = 8000000;
    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &arg);
    unsigned char wbuf[8] = {CAN_RESET, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00};
    unsigned char rbuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    struct SpiIocMsg iocmsg = {0};
    struct SpiMsg msg = {0};
    msg.wbuf = wbuf;
    msg.rbuf = rbuf;
    msg.len = 1;
    msg.speed=8000000;
    iocmsg.msg = &msg;
    iocmsg.count = 1;
    ioctl(fd, SPI_IOC_MESSAGE, &iocmsg);

    // MCP2515_ReadByte(fd, CANCTRL);
    // MCP2515_ReadByte(fd, CANSTAT);
    MCP2515_Init(fd);
    // write(fd, wbuf, 4);
    // read(fd, &wbuf[4], 2);
    // printf("%x %x\n", wbuf[4], wbuf[5]);
    
    unsigned char buf[8] = {0x02, 0x02, 0x03, 0x04, 0x0C, 0x09, 0x01, 0x09};
    int count = 1;
    while (count--)
    {   buf[0] = count;
        CAN_Send_Buffer(fd, buf, 4);
        sleep(1);
    }
    
    

    close(fd);
    printf("\n************************************************\n\n");
    
    return 0;
}